package com.niiwoo.civet.trade.service.dubbo.loan.credit;

import com.alibaba.dubbo.config.annotation.Service;
import com.alibaba.fastjson.JSON;
import com.niiwoo.civet.trade.constant.LoanFlowMqConstant;
import com.niiwoo.civet.trade.dao.entity.ProjectFlowExecuteRuntime;
import com.niiwoo.civet.trade.dto.common.TcCreditAmountResultDTO;
import com.niiwoo.civet.trade.dto.request.loan.ProjectFlowExecuteRuntimeDTO;
import com.niiwoo.civet.trade.enums.LoanNodeTypeEnum;
import com.niiwoo.civet.trade.enums.ProjectFlowExecuteRuntimeNodeStatusEnum;
import com.niiwoo.civet.trade.enums.ProjectTypeEnum;
import com.niiwoo.civet.trade.service.loan.credit.CreditAmountDubboService;
import com.niiwoo.civet.trade.service.local.flowexecute.ProjectFlowExecuteService;
import com.niiwoo.civet.trade.service.local.loan.credit.CreditAmountLocalService;
import com.niiwoo.civet.trade.service.local.project.ProjectLocalService;
import com.niiwoo.tripod.tiancheng.enums.AgainstFakeErrorCodeEnum;
import com.niiwoo.tripod.tiancheng.enums.FunctionCodeEnum;
import com.niiwoo.tripod.tiancheng.response.common.AgainstFakeV2Response;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;

import java.math.BigDecimal;

/**
 * V5.1.5  授信额度评分卡
 * Created by dell on 2018/4/19.
 * Description：civet-app
 */
@Slf4j
@Service(version = "1.0.0")
public class CreditAmountDubboServiceImpl implements CreditAmountDubboService {

    @Autowired
    private CreditAmountLocalService creditAmountLocalService;
    @Autowired
    private ProjectFlowExecuteService projectFlowExecuteService;
    @Autowired
    private ProjectLocalService projectLocalService;

    /**
     * 获取授信额度
     * @param flowExecuteId
     */
    @Override
    public void getCreditAmount(Long flowExecuteId) {
        ProjectFlowExecuteRuntime projectFlowExecuteRuntime = creditAmountLocalService.queryProjectFlowExecuteRuntime(flowExecuteId);
        if(projectFlowExecuteRuntime == null) {
            log.warn("【获取授信额度】流程不存在, flowExecuteId={}", flowExecuteId);
            return;
        }

        StringBuffer errMsg = new StringBuffer("flowExecuteId=").append(flowExecuteId);
        try {
            //发起授信申请
            AgainstFakeV2Response againstFakeV2Response = null;
            Byte projectType = projectFlowExecuteRuntime.getProjectType();
            //小易借
            if (ProjectTypeEnum.SMALL_LOAN.getValue().equals(projectType)){
                againstFakeV2Response = creditAmountLocalService.callTcSmallLoanCredit(projectFlowExecuteRuntime);

            //社保贷
            } else if (ProjectTypeEnum.SOCIAL_SECURITY_LOAN.getValue().equals(projectType)) {
                againstFakeV2Response = creditAmountLocalService.callTcSocialSecurityCredit(projectFlowExecuteRuntime);

            //信用卡贷
            } else if (ProjectTypeEnum.CREDIT_CARD_LOAN.getValue().equals(projectType)) {
                againstFakeV2Response = creditAmountLocalService.callTcCreditCardLoanCredit(projectFlowExecuteRuntime);
            }
            // 消费贷
            else if (ProjectTypeEnum.CONSUME_LOAN.getValue().equals(projectType)) {
            	againstFakeV2Response = creditAmountLocalService.callTcConsumeLoanCredit(projectFlowExecuteRuntime);
            } else {
                log.error("【获取授信额度】借款类型不正确 flowExecuteId={} projectType={}", flowExecuteId, projectType);
            }
            log.info("发起授信额度获取结果{}, flowExecuteId={}, againstFakeV2Response={}", projectType, flowExecuteId, JSON.toJSONString(againstFakeV2Response));
            errMsg.append("评分卡请求响应错误码:");
            errMsg.append(againstFakeV2Response.getCode());

            // 请求响应成功，更新节点到下一步
            if(AgainstFakeErrorCodeEnum.SUCCESS.getErrorCode() == againstFakeV2Response.getCode()) {
                projectFlowExecuteService.initNextStepProjectFlowExecute(flowExecuteId, LoanNodeTypeEnum.LOAN_LIMIT_SCORE, LoanNodeTypeEnum.LOAN_LIMIT_SCORE_BACK, null);

            //请求响应（参数错误、数据异常、其它错误）结束流程
            } else if (AgainstFakeErrorCodeEnum.PRAM_ERROR.getErrorCode() == againstFakeV2Response.getCode() ||
                        AgainstFakeErrorCodeEnum.DATA_ABNORMAL.getErrorCode() == againstFakeV2Response.getCode() ||
                        AgainstFakeErrorCodeEnum.OTHER_ERROR.getErrorCode() == againstFakeV2Response.getCode()){
                projectFlowExecuteService.failEndProjectFlowExecute(flowExecuteId, LoanNodeTypeEnum.LOAN_LIMIT_SCORE, errMsg.toString());

            // 请求响应（获取数据超时、服务忙，稍后重试）更新为异常流程，后续重试
            } else {
                projectFlowExecuteService.updateProjectFlowExecuteRuntime(flowExecuteId, LoanNodeTypeEnum.LOAN_LIMIT_SCORE, ProjectFlowExecuteRuntimeNodeStatusEnum.EXCEPTION, errMsg.toString());
            }
        } catch (Exception e) {
            errMsg.append("发起授信额度获取结果执行异常");
            errMsg.append(e.getMessage());
            projectFlowExecuteService.updateProjectFlowExecuteRuntime(flowExecuteId, LoanNodeTypeEnum.LOAN_LIMIT_SCORE, ProjectFlowExecuteRuntimeNodeStatusEnum.EXCEPTION, errMsg.toString());
            log.error("发起授信额度获取结果执行异常 projectFlowExecuteRuntime={}", JSON.toJSONString(projectFlowExecuteRuntime));
        }
    }

    /**
     * 获取提额授信额度
     * @param flowExecuteId
     */
    @Override
    public void getTeCditAmount(Long flowExecuteId) {
        log.info("getTeCditAmount.flowExecuteId={}",flowExecuteId);
        ProjectFlowExecuteRuntime projectFlowExecuteRuntime = creditAmountLocalService.queryProjectFlowExecuteRuntime(flowExecuteId);
        if(projectFlowExecuteRuntime == null) {
            log.warn("【获取提额授信额度】流程不存在, flowExecuteId={}", flowExecuteId);
            return;
        }

        Integer retryTimes = projectFlowExecuteRuntime.getRetryTimes();

        StringBuffer errMsg = new StringBuffer("flowExecuteId=").append(flowExecuteId);
        try {
            //发起授信申请
            AgainstFakeV2Response againstFakeV2Response = null;
            Byte projectType = projectFlowExecuteRuntime.getProjectType();
            
            // 小易借
            if (ProjectTypeEnum.SOCIAL_SECURITY_LOAN.getValue().equals(projectType)) {
                againstFakeV2Response = creditAmountLocalService.callTcSocialSecurityCreditForTe(projectFlowExecuteRuntime);
            }
            // 信用卡贷
            else if (ProjectTypeEnum.CREDIT_CARD_LOAN.getValue().equals(projectType)) {
                againstFakeV2Response = creditAmountLocalService.callTcCreditCardLoanCreditForTe(projectFlowExecuteRuntime);
            }
            // 其它
            else {
            	againstFakeV2Response = new AgainstFakeV2Response();
            	againstFakeV2Response.setCode(AgainstFakeErrorCodeEnum.OTHER_ERROR.getErrorCode());
                log.error("【获取提额授信额度】借款类型不正确 flowExecuteId={} projectType={}", flowExecuteId, projectType);
            }
            log.info("发起提额授信额度获取结果{}, flowExecuteId={}, againstFakeV2Response={}", projectType, flowExecuteId, JSON.toJSONString(againstFakeV2Response));
            errMsg.append("评分卡请求响应错误码:");
            errMsg.append(againstFakeV2Response.getCode());

            // 请求响应成功，更新节点到下一步
            if(AgainstFakeErrorCodeEnum.SUCCESS.getErrorCode() == againstFakeV2Response.getCode()) {
                projectFlowExecuteService.initNextStepProjectFlowExecute(flowExecuteId, LoanNodeTypeEnum.LOAN_TE_LIMIT_SCORE, LoanNodeTypeEnum.LOAN_TE_LIMIT_SCORE_BACK, null);

                //请求响应（参数错误、数据异常、其它错误）结束流程
            } else if (AgainstFakeErrorCodeEnum.PRAM_ERROR.getErrorCode() == againstFakeV2Response.getCode() ||
                    AgainstFakeErrorCodeEnum.DATA_ABNORMAL.getErrorCode() == againstFakeV2Response.getCode() ||
                    AgainstFakeErrorCodeEnum.OTHER_ERROR.getErrorCode() == againstFakeV2Response.getCode()){
                //projectFlowExecuteService.failEndProjectFlowExecute(flowExecuteId, LoanNodeTypeEnum.LOAN_TE_LIMIT_SCORE, errMsg.toString());

                //TODO:wukeTODO：添加获取额度评分卡失败处理逻辑
                creditAmountLocalService.teFlowErrorProcess(LoanNodeTypeEnum.LOAN_TE_LIMIT_SCORE, flowExecuteId, projectFlowExecuteRuntime.getBorrowUserId(), projectFlowExecuteRuntime.getProjectId(), errMsg.toString());

                // 请求响应（获取数据超时、服务忙，稍后重试）更新为异常流程，后续重试
            } else {
                projectFlowExecuteService.updateProjectFlowExecuteRuntime(flowExecuteId, LoanNodeTypeEnum.LOAN_TE_LIMIT_SCORE, ProjectFlowExecuteRuntimeNodeStatusEnum.EXCEPTION, errMsg.toString(),(retryTimes+1));
            }
        } catch (Exception e) {
            log.error("发起提额授信额度获取结果执行异常 projectFlowExecuteRuntime={}", JSON.toJSONString(projectFlowExecuteRuntime),e);
            errMsg.append("发起提额授信额度获取结果执行异常");
            errMsg.append(e.getMessage());
            projectFlowExecuteService.updateProjectFlowExecuteRuntime(flowExecuteId, LoanNodeTypeEnum.LOAN_TE_LIMIT_SCORE, ProjectFlowExecuteRuntimeNodeStatusEnum.EXCEPTION, errMsg.toString(),(retryTimes+1));
        }
    }

    /**
     * 重新发起天秤额度评分卡调用（重试只针对于发起天秤请求的场景）
     */
    @Override
    public void retryCallTcAmountScoreCard(ProjectFlowExecuteRuntimeDTO flowExecuteRuntimeDTO) {
        Long flowExecuteId = flowExecuteRuntimeDTO.getFlowExecuteId();

        //超过三次，直接流标无需重试
        StringBuffer errMsg = new StringBuffer("flowExecuteId=").append(flowExecuteId);
        if(flowExecuteRuntimeDTO.getRetryTimes() >= 3){
            //结束流程
            errMsg.append("评分卡重试超过3次");
            projectFlowExecuteService.failEndProjectFlowExecute(flowExecuteId, LoanNodeTypeEnum.LOAN_LIMIT_SCORE_BACK, errMsg.toString());
            return;
        }

        //再次发起授信申请
        this.getCreditAmount(flowExecuteRuntimeDTO.getFlowExecuteId());
    }

    @Override
    public void teRetryCallTcAmountScoreCard(ProjectFlowExecuteRuntimeDTO flowExecuteRuntimeDTO) {
        Long flowExecuteId = flowExecuteRuntimeDTO.getFlowExecuteId();

        //超过三次，直接流标无需重试
        StringBuffer errMsg = new StringBuffer("flowExecuteId=").append(flowExecuteId);
        if(flowExecuteRuntimeDTO.getRetryTimes() >= 3){
            //结束流程
            errMsg.append("提额评分卡重试超过3次");
            //projectFlowExecuteService.failEndProjectFlowExecute(flowExecuteId, LoanNodeTypeEnum.LOAN_TE_LIMIT_SCORE, errMsg.toString());
            creditAmountLocalService.teFlowErrorProcess(LoanNodeTypeEnum.LOAN_TE_LIMIT_SCORE, flowExecuteId, flowExecuteRuntimeDTO.getBorrowUserId(), flowExecuteRuntimeDTO.getProjectId(), errMsg.toString());
            return;
        }

        //再次发起提额授信申请
        this.getTeCditAmount(flowExecuteRuntimeDTO.getFlowExecuteId());
    }

    /**
     * 天秤授信额度评分卡回调
     * @param functionCode
     * @param amountResultDTO
     */
    @Override
    public void scoreCardTcCallback(String functionCode, TcCreditAmountResultDTO amountResultDTO) {
        Long flowExecuteId = Long.valueOf(amountResultDTO.getReserve());
        ProjectFlowExecuteRuntime projectFlowExecuteRuntime = creditAmountLocalService.queryProjectFlowExecuteRuntime(flowExecuteId);

        //如果提额认证标的
        if(FunctionCodeEnum.LIBRA_SOCIAL_SECURITY_TE_LOAN.getHeadFunctionCode().equals(functionCode) ||
                FunctionCodeEnum.LIBRA_CREDIT_CARD_TE_LOAN.getHeadFunctionCode().equals(functionCode)){
            teScoreCardTcCallback(functionCode,amountResultDTO,projectFlowExecuteRuntime);
        }else {
            nonTeScoreCardTcCallback(functionCode,amountResultDTO,projectFlowExecuteRuntime);
        }
    }

    public void teScoreCardTcCallback(String functionCode,TcCreditAmountResultDTO amountResultDTO,ProjectFlowExecuteRuntime projectFlowExecuteRuntime){
        Long flowExecuteId = Long.valueOf(amountResultDTO.getReserve());
        //如果天秤回调时，发现当前节点不属于本业务逻辑，说明天秤属于重复调用，不予处理
        if (LoanNodeTypeEnum.LOAN_TE_LIMIT_SCORE.getId() != projectFlowExecuteRuntime.getNodeId() &&
                LoanNodeTypeEnum.LOAN_TE_LIMIT_SCORE_BACK.getId() != projectFlowExecuteRuntime.getNodeId()) {
            log.error("天秤提额授信额度评分卡回调,流程节点异常.");
            return;
        }

        try {

            if(AgainstFakeErrorCodeEnum.SUCCESS.getErrorCode() == amountResultDTO.getStatus()) {

                creditAmountLocalService.teScoreCardTcCallback(functionCode, amountResultDTO);

                //请求响应（参数错误、数据异常、其它错误）结束流程
            } else if (AgainstFakeErrorCodeEnum.PRAM_ERROR.getErrorCode() == amountResultDTO.getStatus() ||
                    AgainstFakeErrorCodeEnum.DATA_ABNORMAL.getErrorCode() == amountResultDTO.getStatus() ||
                    AgainstFakeErrorCodeEnum.OTHER_ERROR.getErrorCode() == amountResultDTO.getStatus()){
                //projectFlowExecuteService.failEndProjectFlowExecute(flowExecuteId, LoanNodeTypeEnum.LOAN_TE_LIMIT_SCORE_BACK, "");

                //TODO:wukeTODO：添加获取额度评分卡失败处理逻辑
                creditAmountLocalService.teFlowErrorProcess(LoanNodeTypeEnum.LOAN_TE_LIMIT_SCORE, flowExecuteId, projectFlowExecuteRuntime.getBorrowUserId(), projectFlowExecuteRuntime.getProjectId(), amountResultDTO.getMessage());

                // 请求响应（获取数据超时、服务忙，稍后重试）更新为异常流程，后续重试
            } else {
                projectFlowExecuteService.updateProjectFlowExecuteRuntime(flowExecuteId, LoanNodeTypeEnum.LOAN_TE_LIMIT_SCORE_BACK, ProjectFlowExecuteRuntimeNodeStatusEnum.EXCEPTION, "");
            }

        } catch (Exception e) {
            log.error("【天秤提额授信额度评分卡回调处理异常：】functionCode={} flowExecuteId={} amountResultDTO={}", functionCode, amountResultDTO.getReserve(), amountResultDTO, e);
            projectFlowExecuteService.updateProjectFlowExecuteRuntime(flowExecuteId, LoanNodeTypeEnum.LOAN_TE_LIMIT_SCORE_BACK, ProjectFlowExecuteRuntimeNodeStatusEnum.EXCEPTION, "");
        }
    }

    public void nonTeScoreCardTcCallback(String functionCode,TcCreditAmountResultDTO amountResultDTO,ProjectFlowExecuteRuntime projectFlowExecuteRuntime){
        Long flowExecuteId = Long.valueOf(amountResultDTO.getReserve());
        //如果天秤回调时，发现当前节点不属于本业务逻辑，说明天秤属于重复调用，不予处理
        if (LoanNodeTypeEnum.LOAN_LIMIT_SCORE.getId() != projectFlowExecuteRuntime.getNodeId() &&
                LoanNodeTypeEnum.LOAN_LIMIT_SCORE_BACK.getId() != projectFlowExecuteRuntime.getNodeId()) {
            log.error("天秤授信额度评分卡回调,流程节点异常.");
            return;
        }

        try {
            //回调成功 继续业务处理
            if (AgainstFakeErrorCodeEnum.SUCCESS.getErrorCode() != amountResultDTO.getStatus()) {
                log.error("天秤授信额度评分卡回调处理异常：{}", amountResultDTO);
                //额度评分卡，不管在什么情况下均
                amountResultDTO.setCreditAmount(new BigDecimal(-1));
            }

            creditAmountLocalService.scoreCardTcCallback(functionCode, amountResultDTO);
        } catch (Exception e) {
            log.error("【天秤授信额度评分卡回调处理异常：】functionCode={} flowExecuteId={} amountResultDTO={}", functionCode, amountResultDTO.getReserve(), amountResultDTO, e);
        } finally {
            //流到下一个流程节点（系统审核）
            projectFlowExecuteService.initNextStepProjectFlowExecute(flowExecuteId, LoanNodeTypeEnum.LOAN_LIMIT_SCORE_BACK, LoanNodeTypeEnum.LOAN_SYSTEM_AUDIT, LoanFlowMqConstant.Queue.LOAN_SYSTEM_AUDIT_QUEUE);
        }
    }

    /**
     * 补漏查询（针对于天秤异步回调超时的场景）
     * @param flowExecuteRuntimeDTO
     */
    @Override
    public void amountScoreBareQuery(ProjectFlowExecuteRuntimeDTO flowExecuteRuntimeDTO){
        creditAmountLocalService.amountScoreBareQuery(flowExecuteRuntimeDTO);
    }

    /**
     * 补漏查询（针对于天秤异步回调超时的场景）
     * @param flowExecuteRuntimeDTO
     */
    @Override
    public void teAmountScoreBareQuery(ProjectFlowExecuteRuntimeDTO flowExecuteRuntimeDTO){
        creditAmountLocalService.teAmountScoreBareQuery(flowExecuteRuntimeDTO);
    }


}




























